#pragma once
#include "../comm/comm.hpp"
#include "../comm/log.hpp"
#include "compiler.hpp"
#include "running.hpp"
// 整合编译和运行逻辑

using namespace Ns_Comm;

class Complie_Run
{
private:
    static void DeleteTemporaryFiles(const std::string &filename)
    {
        std::string _src = PathTool::SplicingCpp(filename);
        if (FileTool::IsExist(_src))
            unlink(_src.c_str());

        std::string _compile_err = PathTool::SplicingCompilerErr(filename);
        if (FileTool::IsExist(_compile_err))
            unlink(_compile_err.c_str());

        std::string _exe = PathTool::SplicingExe(filename);
        if (FileTool::IsExist(_exe))
            unlink(_exe.c_str());

        std::string _stdin = PathTool::SplicingExeStdin(filename);
        if (FileTool::IsExist(_stdin))
            unlink(_stdin.c_str());

        std::string _stdout = PathTool::SplicingExeStdout(filename);
        if (FileTool::IsExist(_stdout))
            unlink(_stdout.c_str());

        std::string _stderr = PathTool::SplicingExeStderr(filename);
        if (FileTool::IsExist(_stderr))
            unlink(_stderr.c_str());
    }

    /*******************************************************************************
     * code < 0：内部错误
     * code == -3：代码编译错误
     * code == 0 ：代码运行完毕
     * code > 0：代码运行异常
     *******************************************************************************/
    static std::string RetCodeDesc(int code, const std::string &filename)
    {
        std::string ret;
        int fd = -1;
        switch (code)
        {
        case Success:
            ret = "运行成功";
            break;
        case UnknownErr:
            ret = "未知错误";
            break; // 服务端错误
        case CodeEmptyErr:
            ret = "代码为空";
            break; // 代码为空
        case ComplieErr:
            fd = FileTool::Open(filename, O_RDONLY);
            ret = FileTool::FileRead(fd);
            break; // 编译错误
        case SIGABRT:
            ret = "内存超出";
            break; // 空间超过上限
        case SIGXCPU:
            ret = "运行超时";
            break; // 代码超时
        case SIGFPE:
            ret = "浮点数溢出";
            break; // 浮点数溢出
        default:
            ret = "Unknown, code : " + std::to_string(code);
            break;
        }
        return ret;
    }

public:
    Complie_Run() {}
    /*******************************************************************************
     * 输入:
     *  1. code: 代码
     *  2. input: 用户提交的用例（扩展）
     *  3. 时间上限
     *  4. 空间上限
     * 输出:
     *  必填：
     *  1. status: 状态码
     *  2. reason: 状态码对应的原因
     *  选填:
     *  1. 代码运行结果输出
     *  2. 代码运行错误结果输出
     *******************************************************************************/
    static void Start(const std::string &in_json, std::string *out_json)
    {
        Json::Value in;
        Json::Reader reader;
        reader.parse(in_json, in);

        // 反序列化
        std::string code = in["code"].asString();
        std::string input = in["input"].asString();
        int cpu_limit = in["cpu_limit"].asInt();
        int mem_limit = in["mem_limit"].asInt();

        int ret_code = 0;                                  // 各个部分的状态码
        std::string filename = FileTool::UniqueFileName(); // 只是一个文件名，不包含后缀
        int wret = true;                                   // 文件写入返回值
        int run_result = 0;                                // 代码运行返回值
        int fd = -1;                                       // 记录写入文件的fd

        if (code.size() == 0)
        {
            ret_code = CodeEmptyErr; // 写入内容为空
            goto END;
        }

        // 创建文件名唯一的.cpp文件，并将用户代码内容输入到该文件中
        umask(0);
        fd = FileTool::Open(PathTool::SplicingCpp(filename), O_CREAT | O_WRONLY | O_TRUNC, 0644);
        if (fd < 0)
        {
            ret_code = UnknownErr; // 打开文件错误，服务端错误
            LOG(LogError, "%s中第%d行打开文件错误\n", __FILE__, __LINE__);
            goto END;
        }

        wret = FileTool::FileWrite(fd, code);
        if (!wret)
        {
            ret_code = UnknownErr; // 写入文件错误，服务端错误
            LOG(LogError, "%s中第%d行写入文件错误\n", __FILE__, __LINE__);
            goto END;
        }

        FileTool::Close(fd);

        // 开始编译代码
        if (!Compiler::CompileForCpp(filename))
        {
            // 差错处理
            ret_code = ComplieErr; // 编译错误
            goto END;
        }

        // 开始运行代码
        run_result = Runner::ExcutedFile(filename, cpu_limit, mem_limit);
        if (run_result < 0)
        {
            // 内部错误
            ret_code = UnknownErr; // 服务端错误
            LOG(LogError, "%s中第%d行代码运行错误\n", __FILE__, __LINE__);
            goto END;
        }
        else if (run_result > 0)
        {
            // 代码运行出现异常
            ret_code = run_result; // 信号
            goto END;
        }
        else
        {
            // 代码运行完毕
            ret_code = 0;
            goto END;
        }

    END:

        // 构建输出部分
        Json::Value out;
        out["code"] = ret_code;
        out["reason"] = RetCodeDesc(ret_code, PathTool::SplicingCompilerErr(filename));
        if (ret_code == 0)
        {
            int stdout_fd = FileTool::Open(PathTool::SplicingExeStdout(filename), O_RDONLY);
            int stderr_fd = FileTool::Open(PathTool::SplicingExeStderr(filename), O_RDONLY);
            out["stdout"] = FileTool::FileRead(stdout_fd);
            out["stderr"] = FileTool::FileRead(stderr_fd);

            FileTool::Close(stdout_fd);
            FileTool::Close(stderr_fd);
        }

        // 删除临时文件
        DeleteTemporaryFiles(filename);
        // 输出部分序列化
        Json::StyledWriter write;
        *out_json = write.write(out);
    }
    ~Complie_Run() {}
};